package com.example.ioc.context;

import com.example.common.utils.Statistics;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;

import java.util.List;


@Slf4j
//@Component //也可以通过Component注入
public class LBeanFactoryPostProcessor implements BeanFactoryPostProcessor, PriorityOrdered {

    private static volatile LBeanFactoryPostProcessor instance;

    private LBeanFactoryPostProcessor(){
        Statistics.logInfo(log);
    }

    public static LBeanFactoryPostProcessor getInstance() {
        if (instance == null) {
            synchronized (LBeanFactoryPostProcessor.class) {
                if (instance == null) {
                    instance = new LBeanFactoryPostProcessor();
                }
            }
        }
        return instance;
    }

    @Override
    public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Statistics.logInfo(log, "postProcessBeanFactory", beanFactory);
        beanFactory.registerScope(LScope.SCOPE_NAME, LScope.getInstance());
        beanFactory.addBeanPostProcessor(LBeanPostProcessor.getInstance());
        beanFactory.addBeanPostProcessor(LDestructionAwareBeanPostProcessor.getInstance());
        beanFactory.addBeanPostProcessor(LInstantiationAwareBeanPostProcessor.getInstance());
        beanFactory.addBeanPostProcessor(LMergedBeanDefinitionPostProcessor.getInstance());
    }

    /**
     * {@link org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, List)}
     * 中有个逻辑，实现{@link PriorityOrdered}的LBeanFactoryPostProcessor,优先调用
     * 但BeanDefinitionRegistryPostProcessor永远比的LBeanFactoryPostProcessor.
     */
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}
